package net.chrone.quickpayapi.api;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;

import org.apache.commons.lang.ArrayUtils;
import org.apache.commons.lang.StringUtils;
import org.apache.log4j.Logger;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.DocumentHelper;
import org.dom4j.Element;
import org.joda.time.DateTime;
import org.springframework.util.DigestUtils;

import net.chrone.quickpayapi.model.CiticWxBaseBean;
import net.chrone.quickpayapi.model.Order;
import net.chrone.quickpayapi.model.PayforTxn;
import net.chrone.quickpayapi.service.RedisService;
import net.chrone.quickpayapi.util.BcdUtil;
import net.chrone.quickpayapi.util.HttpClientHelper;
import net.chrone.quickpayapi.util.HttpResponse;
import net.chrone.quickpayapi.util.Object2Xml;
import net.chrone.quickpayapi.util.SdkUtil;
import net.chrone.quickpayapi.util.SignatureUtil;
import net.chrone.quickpayapi.util.SocketClient;


/**
 * 腾势中信微信通道
 * @author Jerry
 */
public class CiticApi {
	
	private static final Logger logger = Logger.getLogger(CiticApi.class);
	
	public static final String SUCCESS_CODE = "0";

	public static CiticWxBaseBean qrpay(Order order){
		logger.debug("请求中信扫码支付接口");
		CiticWxBaseBean requestBean = new CiticWxBaseBean();
		requestBean.setService("pay.weixin.native");
		requestBean.setMch_id(SdkUtil.getStringValue("citicMchntId"));
		requestBean.setOut_trade_no(order.getOrderNo());
		requestBean.setBody(order.getSubject());
		requestBean.setTotal_fee(order.getAmount());
		requestBean.setMch_create_ip("192.168.1.1");
		requestBean.setNotify_url(SdkUtil.getStringValue("citicNotifyUrl"));
		requestBean.setNonce_str(SdkUtil.getNonceStr());
		requestBean.setSign(sign(requestBean));//签名
		return requestWeChat(requestBean,SdkUtil.getStringValue("citicReqUrl"));
	}
	
	
	public static String payfor(PayforTxn txn,RedisService redisService){
		try{
			DateTime dateTime = new DateTime();
			StringBuffer body = new StringBuffer("<?xml version=\"1.0\" encoding=\"GBK\"?><root>");
			body.append("<Head>")
			.append("<TransCode>").append("DSF00001").append("</TransCode>")
			.append("<RefID>").append(txn.getTxnId()).append("</RefID>")
			.append("<Date>").append(dateTime.toString("yyyyMMdd")).append("</Date>")
			.append("<Time>").append(dateTime.toString("HHmmss")).append("</Time>")
			.append("</Head>")
			.append("<Request>")
			.append("<MerchID>").append(SdkUtil.getStringValue("umsMchntId")).append("</MerchID>")
			.append("<DevID>").append(SdkUtil.getStringValue("umsDevId")).append("</DevID>")
			.append("<InAcctNo>").append(txn.getCardNo()).append("</InAcctNo>")
			.append("<InAcctName>").append(txn.getAccountName()).append("</InAcctName>")
			.append("<InAcctType>").append(txn.getCompanyAcct()==0?1:0).append("</InAcctType>")
			.append("<InBankName>").append(redisService.findRootBank(txn.getBankCd()).getBankNm()).append("</InBankName>")
//			.append("<InBankName>").append("中国建设银行").append("</InBankName>")
			.append("<InBankNo>").append(txn.getPmsBankCd()).append("</InBankNo>")
			.append("<TranAmt>").append(StringUtils.leftPad(txn.getAmount()+"", 12, "0")).append("</TranAmt>")
			.append("</Request></root>");
			logger.debug("body msg:"+body.toString());
			int msgLen = 34+body.toString().getBytes("GBK").length;//报文总长度
			String hexStr = Integer.toHexString(msgLen);
			byte[] tempByte = null;
			tempByte=ArrayUtils.addAll(tempByte, BcdUtil.str2Bcd(hexStr, false));//报文长度位
			tempByte=ArrayUtils.addAll(tempByte, BcdUtil.str2Bcd(SdkUtil.getStringValue("umsTpdu"), true));//TPDU
			tempByte=ArrayUtils.addAll(tempByte, "DSF00001".getBytes());//交易代码
			tempByte=ArrayUtils.addAll(tempByte, "000000000000000000000".getBytes());//唯一流水
			tempByte=ArrayUtils.addAll(tempByte, body.toString().getBytes("GBK"));//报文体
			byte[] respData = SocketClient.send2UMS(tempByte);//发送至银商
			byte[] xmlData = ArrayUtils.subarray(respData, 40,respData.length-1);
			String xml = new String(xmlData,"GBK");
			logger.debug("银商返回xml："+xml);
			String respInfo = parseXml(xml);
			return respInfo;
		}catch (Exception e) {
			logger.error("请求银商代付接口出错");
			e.printStackTrace();
		}
		return null;
	}
	
	/**
	 * 代付查询
	 * @param txn：付款交易
	 * @param queryId:查询交易号
	 * @return
	 */
	public static String payforQuery(PayforTxn txn,String queryId){
		try{
			DateTime dateTime = new DateTime();
			StringBuffer body = new StringBuffer("<?xml version=\"1.0\" encoding=\"GBK\"?><root>");
			body.append("<Head>")
			.append("<TransCode>").append("DSF00002").append("</TransCode>")
			.append("<RefID>").append(queryId).append("</RefID>")
			.append("<Date>").append(dateTime.toString("yyyyMMdd")).append("</Date>")
			.append("<Time>").append(dateTime.toString("HHmmss")).append("</Time>")
			.append("</Head>")
			.append("<Request>")
			.append("<MerchID>").append(SdkUtil.getStringValue("umsMchntId")).append("</MerchID>")
			.append("<DevID>").append(SdkUtil.getStringValue("umsDevId")).append("</DevID>")
			.append("<OriTranDate>").append(txn.getTxnDt()).append("</OriTranDate>")
			.append("<OriRefID>").append(txn.getTxnId()).append("</OriRefID>")
			.append("</Request></root>");
			logger.debug("body msg:"+body.toString());
			int msgLen = 34+body.toString().getBytes("GBK").length;//报文总长度
			String hexStr = Integer.toHexString(msgLen);
			byte[] tempByte = null;
			tempByte=ArrayUtils.addAll(tempByte, BcdUtil.str2Bcd(hexStr, false));//报文长度位
			tempByte=ArrayUtils.addAll(tempByte, BcdUtil.str2Bcd(SdkUtil.getStringValue("umsTpdu"), true));//TPDU
			tempByte=ArrayUtils.addAll(tempByte, "DSF00002".getBytes());//交易代码
			tempByte=ArrayUtils.addAll(tempByte, "000000000000000000000".getBytes());//唯一流水
			tempByte=ArrayUtils.addAll(tempByte, body.toString().getBytes("GBK"));//报文体
			byte[] respData = SocketClient.send2UMS(tempByte);//发送至银商
			byte[] xmlData = ArrayUtils.subarray(respData, 40,respData.length-1);
			String xml = new String(xmlData,"GBK");
			logger.debug("银商返回xml："+xml);
			String respInfo = parseXml(xml);
			return respInfo;
		}catch (Exception e) {
			e.printStackTrace();
		}
		return null;
	}
	
	/**
	 * 请求威富通
	 * @param requestBean
	 * @param url
	 * @return
	 */
	private static CiticWxBaseBean requestWeChat(CiticWxBaseBean requestBean,String url){
		String xml = Object2Xml.object2xml(requestBean);
		xml=xml.replaceAll("__", "_");
		logger.debug("request xml = " + xml);
		HttpResponse response = HttpClientHelper.doHttp(url, HttpClientHelper.POST, "utf-8", xml, "60000");
		if(StringUtils.isNotEmpty(response.getRspStr())){
			String result = response.getRspStr();
			logger.debug("result xml = " + result);
			CiticWxBaseBean responseBean = (CiticWxBaseBean) Object2Xml.xml2Object(result, CiticWxBaseBean.class);
			return responseBean;
		}
		return null;
	}
	
	/**
	 * 签名
	 * @param bean
	 */
	public static String sign(CiticWxBaseBean bean){
		Map<String,String> map = new HashMap<String, String>();
		Method[] methods = CiticWxBaseBean.class.getMethods();
		for(Method method:methods){
			String methodName = method.getName();
			if(methodName.startsWith("get") && !methodName.equals("getClass")){
				try {
					Object object = method.invoke(bean, null);
					if(object!=null && StringUtils.isNotEmpty(object.toString()) && !"getSign".equals(methodName)){
						String field = methodName.substring(3).toLowerCase();
						map.put(field, object.toString());
					}
				} catch (IllegalArgumentException e) {
					e.printStackTrace();
				} catch (IllegalAccessException e) {
					e.printStackTrace();
				} catch (InvocationTargetException e) {
					e.printStackTrace();
				}
			}
		}
		String bigStr = SignatureUtil.hex(map)+"&key="+SdkUtil.getStringValue("citicKey");
		String sign = DigestUtils.md5DigestAsHex(bigStr.getBytes());
		return sign;
	}
	
	/**
	 * 解析结果
	 * @param xml
	 * @return
	 */
	private static String parseXml(String xml){
		try {
			Document doc = DocumentHelper.parseText(xml);
			Element rootElement = doc.getRootElement();
			String code = rootElement.element("Return").element("Results").element("Code").getText();
			String info = rootElement.element("Return").element("Results").element("Info").getText();
			return code+":"+info;
		} catch (DocumentException e) {
			logger.debug("解析银商应答保温出错");
			e.printStackTrace();
		}
		return null;
	}
	
	public static void main(String[] args) {
//		Order order = new Order();
//		order.setAmount(1);
//		order.setOrderNo(System.currentTimeMillis()+"");
//		CiticWxBaseBean bean = qrpay(order, "全景支付");
//		System.out.println(bean.getCodeUrl());
		
		PayforTxn txn = new PayforTxn();
		txn.setTxnId("1478157485123");
		txn.setTxnDt("20161103");
		txn.setCardNo("6228481002117546213");
		txn.setAccountName("谭超");
		txn.setCompanyAcct(0);
		txn.setAmount(994);
		txn.setPmsBankCd("123412341234");
		txn.setBankCd("103");
//		payfor(txn,null);
		
//		payforQuery(txn, System.currentTimeMillis()+"");
		
		parseXml("<?xml version=\"1.0\" encoding=\"GBK\"?><root><Head><TransCode>DSF00002</TransCode><RefID>1478160811175</RefID><Operator></Operator><Date>20161103</Date><Time>161331</Time></Head><Return><Results><Code>000000</Code><Info>交易成功</Info></Results> <BillDate>20161103</BillDate></Return></root>");
	}
}
